home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / biblio / bibtex / utils / bibclean / strtol.c < prev    next >
C/C++ Source or Header  |  1992-10-06  |  5KB  |  259 lines

  1. /* -*-C-*- strtol.c */
  2. /*-->strtol*/
  3. /**********************************************************************/
  4. /****************************** strtol ********************************/
  5. /**********************************************************************/
  6.  
  7. #include "os.h"
  8. #include "xctype.h"
  9. #include "xstring.h"
  10. #include "xstdlib.h"
  11.  
  12. RCSID("$Id: strtol.c,v 1.6 1992/10/08 01:42:01 beebe Exp beebe $")
  13.  
  14. /* $Log: strtol.c,v $
  15.  * Revision 1.6  1992/10/08  01:42:01  beebe
  16.  * Update for C++.
  17.  *
  18.  * Revision 1.5  1992/07/10  17:58:12  beebe
  19.  * Modify one output format.
  20.  *
  21.  * Revision 1.4  1992/03/06  14:58:06  beebe
  22.  * Complete two-month long development of version 3.0.114.  See
  23.  * 00revhst.txt for details.
  24.  *
  25.  * Revision 1.3  1992/02/29  19:42:20  beebe
  26.  * Update for version 3.0.114 [29-Feb-1992] following two-month
  27.  * major overhaul and compilation testing on numerous machines.
  28.  *
  29.  * Revision 1.2  1992/01/22  02:31:19  beebe
  30.  * Add RCSID() and RCS comment log.
  31.  * */ 
  32.  
  33. #define IN(l,a,r) (((l) <= (a)) && ((a) <= (r)))
  34.  
  35. /* This is a simple implementation of Standard C strtol().  A library
  36. version should be programmed with more care. */
  37.  
  38. long
  39. #if STDC
  40. strtol(
  41. const char  *nptr,
  42. char** endptr,
  43. int base
  44. )
  45. #else /* NOT STDC */
  46. strtol(nptr,endptr,base)
  47. const char  *nptr;
  48. char** endptr;
  49. int base;
  50. #endif /* STDC */
  51. {
  52.     int            c;        /* current character value */
  53.     int            digit;        /* digit value */
  54.     static const char    *digits = "0123456789abcdefghijklmnopqrstuvxwyz";
  55.     int            negative; /* 0 for positive, non-0 for negative */
  56.     long        number;        /* the accumulating number */
  57.     const char        *pos;        /* pointer into digit list */
  58.     const char        *q;        /* pointer past end of digits */
  59.  
  60.     if (!(IN(2,base,36) || (base == 0)))
  61.     {
  62.     if (endptr != (char**)NULL)
  63.         *endptr = (char*)nptr;
  64.     return (0L);
  65.     }
  66.  
  67.     while (isspace(*nptr))
  68.     nptr++;                /* ignore leading whitespace */
  69.  
  70.     switch (*nptr)            /* set number sign */
  71.     {
  72.     case '-':
  73.     negative = -1;
  74.     nptr++;
  75.     break;
  76.  
  77.     case '+':
  78.     negative = 0;
  79.     nptr++;
  80.     break;
  81.  
  82.     default:
  83.     negative = 0;
  84.     break;
  85.     }
  86.  
  87.     q = nptr;
  88.     if (base == 0)            /* variable base; set by lookahead */
  89.     {
  90.     if (*q == '0')
  91.         base = ((*(q+1) == 'x') || (*(q+1) == 'X')) ? 16 : 8;
  92.     else
  93.         base = 10;
  94.     }
  95.  
  96.     /* eliminate optional "0x" or "0X" prefix */
  97.  
  98.     if (    (base == 16) &&
  99.     (*q == '0') &&
  100.     ((*(q+1) == 'x') || (*(q+1) == 'X')) )
  101.     q += 2;
  102.  
  103.     number = 0L;
  104.  
  105.     /* Number conversion is done by shifting rather than multiplication
  106.        when the base is a power of 2, in order that the results not be
  107.        impacted by integer overflow. */
  108.     switch (base)
  109.     {
  110.     case 2:
  111.     while (IN('0',*q,'1'))
  112.     {
  113.         number <<= 1;
  114.         number |= *q - '0';
  115.         q++;
  116.     }
  117.     break;
  118.  
  119.     case 4:
  120.     while (IN('0',*q,'3'))
  121.     {
  122.         number <<= 2;
  123.         number |= *q - '0';
  124.         q++;
  125.     }
  126.     break;
  127.  
  128.  
  129.     case 8:
  130.     while (IN('0',*q,'7'))
  131.     {
  132.         number <<= 3;
  133.         number |= *q - '0';
  134.         q++;
  135.     }
  136.     break;
  137.  
  138.  
  139.     case 16:
  140.     for (;;)
  141.     {
  142.         if (!*q)
  143.         break;
  144.         c = (unsigned)*q;
  145.         if (isupper(c))
  146.         c = tolower(c);
  147.         pos = strchr(digits,c);
  148.         if (pos == (char*)NULL)
  149.         break;
  150.         digit = (int)(pos - digits);
  151.         if (!IN(0,digit,15))
  152.         break;
  153.         number <<= 4;
  154.         number |= digit;
  155.         q++;
  156.     }
  157.     break;
  158.  
  159.  
  160.     case 32:
  161.     for (;;)
  162.     {
  163.         if (!*q)
  164.         break;
  165.         c = (unsigned)*q;
  166.         if (isupper(c))
  167.         c = tolower(c);
  168.         pos = strchr(digits,c);
  169.         if (pos == (char*)NULL)
  170.         break;
  171.         digit = (int)(pos - digits);
  172.         if (!IN(0,digit,31))
  173.         break;
  174.         number <<= 5;
  175.         number |= digit;
  176.         q++;
  177.     }
  178.     break;
  179.  
  180.     default:        /* all other bases done by multiplication */
  181.     for (;;)    /* accumulate negative so most negative */
  182.     {        /* number on two's-complement is handled */
  183.         if (!*q)
  184.         break;
  185.         c = (unsigned)*q;
  186.         if (isupper(c))
  187.         c = tolower(c);
  188.         pos = strchr(digits,c);
  189.         if (pos == (char*)NULL)
  190.         break;
  191.         digit = (int)(pos - digits);
  192.         if (!IN(0,digit,base-1))
  193.         break;
  194.         number *= base;
  195.         number -= digit;
  196.         q++;
  197.     }
  198.     if (endptr != (char**)NULL)
  199.         *endptr = (char*)q;
  200.     if (negative)
  201.         return(number);
  202.     number = -number;
  203.     break;
  204.     }
  205.     if (negative)
  206.     number = -number;
  207.     if (endptr != (char**)NULL)
  208.     *endptr = (char*)q;
  209.     return (number);
  210. }
  211.  
  212. #ifdef TEST
  213. /***********************************************************************
  214. Simple test program for strtol().   Values are read from stdin, and the
  215. results in different bases are echoed to stdout.
  216. ***********************************************************************/
  217.  
  218. #ifndef EXIT_SUCCESS
  219. #define EXIT_SUCCESS 0
  220. #endif /* EXIT_SUCCESS */
  221.  
  222.  
  223. int
  224. #if STDC
  225. main(
  226. int            argc,
  227. char            *argv[]
  228. )
  229. #else /* NOT STDC */
  230. main(argc,argv)
  231. int            argc;
  232. char            *argv[];
  233. #endif /* STDC */
  234. {
  235.     char        s[25];
  236.     char        *endptr;
  237.     long        n;
  238.     int            k;
  239.     static int        base[] =
  240.     {
  241.     0, 2, 4, 8, 10, 16, 32, 36, 5,
  242.     };
  243.  
  244.  
  245.     while (gets(s) != (char*)NULL)
  246.     {
  247.     for (k = 0; k < sizeof(base)/sizeof(base[0]); ++k)
  248.     {
  249.         n = strtol(s,&endptr,base[k]);
  250.         (void)printf(
  251.             "strtol(,,%d):  %s -> 16#%lx  8#%lo  10#%ld  Rem = [%s]\n",
  252.             base[k],s,n,n,n,endptr);
  253.     }
  254.     }
  255.     exit (EXIT_SUCCESS);
  256.     return (0);
  257. }
  258. #endif /* TEST */
  259.